﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.Drawing;
using MyAlbum.Model;
using MyAlbum.Services;
using System.Text.RegularExpressions;
using MyAlbum.Utility;

namespace PersonalAlbum.Controllers
{
    public class EntryController : ApplicationController
    {
        private IEntryService _entryService;
        private IAlbumService _albumService;
        private IUser _user;
        private IConfiguration _config;
        public EntryController()
            : this(ObjectFactory.GetInstance<IEntryService>(),
                ObjectFactory.GetInstance<IAlbumService>(),
                ObjectFactory.GetInstance<IUser>(),
                ObjectFactory.GetInstance<IConfiguration>())
        { }

        public EntryController(IEntryService entryService,
            IAlbumService albumService,
            IUser user,
            IConfiguration config)
        {
            this._config = config;
            this._entryService = entryService;
            this._albumService = albumService;
            this._user = user;
        }

        [AcceptVerbs(HttpVerbs.Post)]
        //[ValidateAn tiForgeryToken()]
        [Authorize(Roles = RolesManager.AdminRoles)]
        public ActionResult Delete(string id)
        {
            string entryId = id;
            string albumId = Request.Params["albumId"];
            string returnUrl = Request.Params["returnUrl"];
            WebLogger.Trace("delete entry " + entryId);

            try
            {
                Entry e = this._entryService.GetItemById(entryId);
                if (e != null)
                {
                    Utils.DeleteImage(e.Uri);
                    Utils.DeleteImage(e.ThumbUri);
                    WebLogger.Trace("entry files deleted");
                    this._entryService.DeleteItem(e);
                    WebLogger.Trace("entry deleted");
                }
                else
                {
                    WebLogger.Warning("entry " + entryId + " not found for delete");
                }
                if (!string.IsNullOrEmpty(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                return RedirectToAction("Index", new { albumId = albumId });
            }
            catch (Exception e1)
            {
                WebLogger.LogError(e1, "error deleting entry");
                TempData["errorMessage"] = ((PersonalAlbumModel)ViewData.Model).Localize("Global.Error");
                return View("Index", LoadData(albumId, null));
            }


        }

        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult ViewByDates(string id)
        {
            string date = id;
            WebLogger.Trace("by dates:" + id);

            var model = (PersonalAlbumModel)ViewData.Model;
            IEnumerable<Entry> entries = this._entryService.GetItems();
            model.Entries = entries;
            if (date != null)
            {
                string[] p = date.Split(new char[] { '-' }, StringSplitOptions.RemoveEmptyEntries);
                if (p.Length == 2)
                {
                    int year;
                    int month;
                    if (int.TryParse(p[0], out year) &&
                        int.TryParse(p[1], out month))
                    {
                        model.Entries = entries.Where(e => e.Date.Year == year && e.Date.Month == month);
                    }
                }
            }
            if (this._user.AllowAdd())
            {
                model.Albums = this._albumService.GetItems();
            }
            return View("Index", model);
        }

        /// <summary>
        /// Search by tags - a click on a tag
        /// </summary>
        /// <param name="tagName"></param>
        /// <returns></returns>
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Tags(string id)
        {
            WebLogger.Trace("tags search " + id);
            string tagName = id;
            var model = (PersonalAlbumModel)ViewData.Model;
            try
            {
                if (!string.IsNullOrEmpty(tagName))
                {
                    model.Entries = this._entryService.GetEntriesByTagName(tagName.Trim());
                    //shouldn't happen for admin...
                    if (model.Entries.Count() == 0)
                    {
                        WebLogger.Warning("no entries found for tag " + HttpUtility.HtmlEncode(tagName));
                        //ObjectFactory.GetInstance<ITagEntryService>().DeleteTagName(tagName);

                    }
                }
                else
                {
                    model.Entries = this._entryService.GetItems(1, model.Configuration.EntriesPerPage);
                }


            }
            catch (Exception e1)
            {
                model.Entries = this._entryService.GetItems(1, model.Configuration.EntriesPerPage);
                WebLogger.LogError(e1, "error searching by tag " + tagName);
            }
            if (this._user.AllowAdd())
            {
                model.Albums = this._albumService.GetItems();
            }

            return View("Index", model);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        //[ValidateAn tiForgeryToken()]
        [Authorize(Roles = RolesManager.AddEntriesRoles)]
        public ActionResult Create(string returnUrl)
        {
            var model = (PersonalAlbumModel)ViewData.Model;
            WebLogger.Trace("create entry");
            string albumId = Request.Params["ParentId"];
            try
            {
                bool autoThumb = Request.Params["autoThumb"] != null &&
                    string.Compare(Request.Params["autoThumb"], "true", true) == 0;
                string tag = Regex.Replace(Request.Params["tag"], @"[^\w,\-]", string.Empty);
                EntryTypes entryType = (EntryTypes)Enum.Parse(typeof(EntryTypes), Request.Params["entryType"]);
                Entry entry = new Entry();

                //we allow update the entry uri in case the file was put on the server manually
                UpdateModel<Entry>(entry, "",
                    new string[] { "Title", "Description", "Visible", "Uri", "ParentId" },
                    new[] { "VideoLen", "Height", "Width", "FileSize", "ThumbWidth", "ThumbHeight" });

                if (entryType == EntryTypes.Image)
                {
                    if (Request.Files["fileData"] != null && Request.Files["fileData"].ContentLength > 0)
                    {
                        int width;
                        int height;
                        entry.Uri = Utils.SaveFile(Request.Files["fileData"], out width, out height);
                        WebLogger.Trace("entry file saved");
                        entry.Width = width;
                        entry.Height = height;
                    }
                    int thumbWidth;
                    int thumbHeight;
                    if (autoThumb)
                    {
                        entry.ThumbUri = CreateThumb(entry.Uri, out thumbWidth, out thumbHeight);
                    }
                    else
                    {
                        entry.ThumbUri = Utils.SaveFile(Request.Files["previewData"], out thumbWidth, out thumbHeight);
                    }
                    WebLogger.Trace("entry thumb saved");
                    entry.ThumbHeight = thumbHeight;
                    entry.ThumbWidth = thumbWidth;
                }
                else
                {
                    int video;
                    if (int.TryParse(Request.Params["VideoLen"], out video))
                    {
                        entry.VideoLen = video;
                    }
                }

                //maybe the size was entered manually for an entry on the server already
                if (entry.Width == 0)
                {
                    int w;
                    if (int.TryParse(Request.Params["Width"], out w))
                    {
                        entry.Width = w;
                    }

                }
                if (entry.Height == 0)
                {
                    int w;
                    if (int.TryParse(Request.Params["Height"], out w))
                    {
                        entry.Height = w;
                    }
                }
                entry.EntryType = (int)entryType;
                entry.Date = DateTime.UtcNow;
                entry.Tags = new List<string>(tag.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)).Select(s => new Tag() { Name = s });
                this._entryService.AddItem(entry, new ModelStateWrapper(ModelState));
                WebLogger.Trace("entry created");
                if (!string.IsNullOrEmpty(returnUrl))
                {
                    return Redirect(returnUrl);
                }
                return RedirectToAction("Index", new { albumId = albumId });
            }
            catch (Exception e1)
            {
                WebLogger.LogError(e1, "error creating entry");
                model.ErrorMessage = model.Localize("Global.Error");
                return View("Index", LoadData(albumId, 1));
            }

        }

        private string CreateThumb(string originalUri, out int thumbWidth, out int thumbHeight)
        {
            Bitmap bmp = new Bitmap(Path.Combine(Server.MapPath(ConfigManager.ImagesPath), originalUri));
            thumbWidth = ((PersonalAlbumModel)ViewData.Model).Configuration.ThumbDefaultWidth;
            thumbHeight = ((PersonalAlbumModel)ViewData.Model).Configuration.ThumbDefaultHeight;
            Image img = bmp.GetThumbnailImage(thumbWidth, thumbHeight, delegate() { return false; }, System.IntPtr.Zero);
            string extension = Path.GetExtension(originalUri);
            string fileName = Guid.NewGuid().ToString("N") + extension;
            img.Save(Server.MapPath(ConfigManager.ImagesPath + "/" + fileName));
            return fileName;
        }

        [Authorize(Roles = RolesManager.AdminRoles)]
        public ActionResult ShowCreate(string parentAlbum)
        {
            var model = (PersonalAlbumModel)ViewData.Model;
            var albums = WebCacheManager.Instance.GetData("albums") as IEnumerable<Album>;
            if (albums == null)
            {
                albums = this._albumService.GetItems();
                WebCacheManager.Instance.InsertData("albums", albums);
            }
            model.Albums = albums;
            model.ReturnUrl = Request.Params["returnUrl"];
            model.ParentAlbum = parentAlbum;
            return PartialView("AddEntry", model);
        }

        [Authorize(Roles = RolesManager.AdminRoles)]
        public ActionResult ShowUpdate(string id)
        {
            var model = (PersonalAlbumModel)ViewData.Model;
            var albums = WebCacheManager.Instance.GetData("albums") as IEnumerable<Album>;
            if (albums == null)
            {
                albums = this._albumService.GetItems();
                WebCacheManager.Instance.InsertData("albums", albums);
            }
            model.Albums = albums;
            model.ReturnUrl = Request.Params["returnUrl"];
            model.CurrentEntry = this._entryService.GetItemById(id);
            return PartialView("EditEntry", model);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        //[ValidateAn tiForgeryToken()]
        [Authorize(Roles = RolesManager.AdminRoles)]
        public ActionResult Update(string id, string returnUrl)
        {
            WebLogger.Trace("update entry");
            var model = (PersonalAlbumModel)ViewData.Model;
            string albumId = Request.Form["ParentId"];
            try
            {
                bool autoThumb = Request.Form["autoThumb"] != null &&
                    string.Compare(Request.Form["autoThumb"], "true", true) == 0;
                string tag = Regex.Replace(Request.Params["tag"], @"[^\w,\-]", string.Empty);
                var entry = this._entryService.GetItemById(id);
                if (entry != null)
                {

                    EntryTypes entryType = (EntryTypes)Enum.Parse(typeof(EntryTypes), Request.Form["entryType"]);
                    UpdateModel<Entry>(entry, "",
                    new string[] { "Title", "Description", "Visible", "Uri", "ParentId" },
                    new[] { "VideoLen", "Height", "Width", "FileSize", "ThumbWidth", "ThumbHeight" });
                    int i;
                    if (int.TryParse(Request.Params["VideoLen"], out i))
                    {
                        entry.VideoLen = i;
                    }
                    if (entryType == EntryTypes.Image)
                    {
                        int width;
                        int height;
                        int thumbWidth;
                        int thumbHeight;
                        if (Request.Files["fileData"] != null && Request.Files["fileData"].ContentLength > 0)
                        {
                            Utils.DeleteImage(entry.Uri);
                            entry.Uri = Utils.SaveFile(Request.Files["fileData"], out width, out height);
                            WebLogger.Trace("entry file saved");

                            entry.Width = width;
                            entry.Height = height;
                            if (autoThumb)
                            {
                                Utils.DeleteImage(entry.ThumbUri);
                                entry.ThumbUri = CreateThumb(entry.Uri, out thumbWidth, out thumbHeight);
                            }
                        }

                        if (!autoThumb &&
                            Request.Files["previewData"] != null &&
                            Request.Files["previewData"].ContentLength > 0)
                        {
                            Utils.DeleteImage(entry.ThumbUri);
                            entry.ThumbUri = Utils.SaveFile(Request.Files["previewData"], out thumbWidth, out thumbHeight);
                            entry.ThumbHeight = thumbHeight;
                            entry.ThumbWidth = thumbWidth;
                            WebLogger.Trace("entry thumb saved");
                        }
                    }
                    if (entry.Width == 0)
                    {
                        int w;
                        if (int.TryParse(Request.Params["Width"], out w))
                        {
                            entry.Width = w;
                        }

                    }
                    if (entry.Height == 0)
                    {
                        int w;
                        if (int.TryParse(Request.Params["Height"], out w))
                        {
                            entry.Height = w;
                        }
                    }
                    entry.EntryType = (int)entryType;

                    if (tag == null)
                    {
                        WebLogger.Warning("Null tag received");
                        tag = string.Empty;
                    }
                    entry.Tags = new List<string>(tag.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)).Select(s => new Tag() { Name = s });
                    this._entryService.UpdateItem(entry, new ModelStateWrapper(ModelState));
                }
                else
                {
                    WebLogger.Warning("No entry found for editing:" + id);
                }

            }
            catch (Exception e1)
            {
                WebLogger.LogError(e1, "error updating entry");
                model.ErrorMessage = model.Localize("Global.Error");
                return View("Index", new { albumId = albumId, pageNumber = 1 });
            }
            if (!string.IsNullOrEmpty(returnUrl))
            {
                return Redirect(returnUrl);
            }
            return RedirectToAction("Index", new { albumId = albumId, pageNumber = 1 });
        }


        //[OutputCache(Duration=12000,VaryByParam="albumId",VaryByCustom="lang")]
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult Index(int page, string albumId)
        {
            WebLogger.Trace("entry index");
            return View(LoadData(albumId, page));
        }

        private PersonalAlbumModel LoadData(string albumId, int? pageNumber)
        {

            PersonalAlbumModel model = (PersonalAlbumModel)ViewData.Model;
            if (pageNumber.HasValue)
            {
                model.CurrentPage = pageNumber.Value;
            }
            else
            {
                model.CurrentPage = 1;
            }
            IEnumerable<Entry> entries;
            if (albumId != null && albumId != "all")
            {
                model.ParentAlbum = albumId;
                entries = this._entryService.GetEntriesByAlbum(albumId, pageNumber.GetValueOrDefault(), model.Configuration.EntriesPerPage);
            }
            else
            {
                entries = this._entryService.GetItems(pageNumber.GetValueOrDefault(), model.Configuration.EntriesPerPage);
            }


            model.Entries = entries;
            return model;
        }

        public ActionResult Details(string id)
        {
            WebLogger.Trace("entry view " + id);
            Entry entry = this._entryService.GetItemById(id);
            if (entry == null)
            {
                WebLogger.Warning("entry " + id + " not found for viewing");
                return View("EntryNotFound");
            }
            else
            {
                var model = ((PersonalAlbumModel)ViewData.Model);
                model.CurrentEntry = entry;
                model.Replies = model.Replies;
                return View(ViewData.Model);
            }
        }

        [ActionOutputCache(3600)]
        public ActionResult RandomImage()
        {
            ((PersonalAlbumModel)ViewData.Model).RandomEntries = ObjectFactory.GetInstance<IEntryService>().LoadRandomEntriesSummary(15);
            return PartialView("RandomImage", ViewData.Model);
        }

        [ActionOutputCache(600)]
        public ActionResult LatestEntry()
        {
            ((PersonalAlbumModel)ViewData.Model).LatestEntry = this._entryService.GetLatestEntry();
            return PartialView("LatestEntry", ViewData.Model);
        }

        [ActionOutputCache(3600)]
        public ActionResult TagsCloud()
        {
            ((PersonalAlbumModel)ViewData.Model).TagsCloud = ObjectFactory.GetInstance<ITagEntryService>().GetTags();
            return PartialView("TagsCloud", ViewData.Model);
        }

        [ActionOutputCache(3000)]
        public ActionResult ByMonths()
        {
            ((PersonalAlbumModel)ViewData.Model).MonthsView = this._entryService.GetEntriesByMonthsSummary();
            return PartialView("ByMonths", ViewData.Model);
        }

        [ActionOutputCache(4200)]
        public ActionResult FlashTagCloud()
        {
            ((PersonalAlbumModel)ViewData.Model).TagsCloud = ObjectFactory.GetInstance<ITagEntryService>().GetTags();
            return PartialView("FlashTagCloud", ViewData.Model);
        }

        [ActionOutputCache(4200)]
        public ActionResult Statistics()
        {
            ((PersonalAlbumModel)ViewData.Model).Statistics = ObjectFactory.GetInstance<IStatisticsService>().Load();
            return PartialView("StatisticsBox", ViewData.Model);
        }
        
    }
}
